#pragma once
#include "cem/boundary_condition.h"
#include "cem/constants.h"
#include "cem/material_database.h"
#include "cem/material_types.h"

#include <optional>
#include <string>
#include <unordered_map>
#include <vector>

// 前向声明 cJSON，避免头文件强依赖第三方头
struct cJSON;

namespace cem
{


// 采样轴规格（对应 JSON: COLLECT_POINT 中的条目）
struct CollectAxisSpec
{
    // 轴名：'x'/'y'/'z'
    char about{'x'};
    // 起点
    double start{0.0};
    // 步长
    double step{0.0};
    // 采样点个数
    int number{0};
};

// 采样点规格：三轴组合（可能部分未提供）
struct CollectPointSpec
{
    bool has_x{false};
    bool has_y{false};
    bool has_z{false};
    CollectAxisSpec x{};
    CollectAxisSpec y{};
    CollectAxisSpec z{};
};

// 采样点坐标值集合（已展开的坐标数组）
struct CollectPointValues
{
    std::vector<double> x_coords;
    std::vector<double> y_coords;
    std::vector<double> z_coords;
};

class ParameterReader
{
public:
    // 函数: parse_cli
    // 作用: 解析命令行参数（示例支持 --mesh 与 --config）
    bool parse_cli(int argc, char ** argv);

    // 函数: load_from_file
    // 作用: 从 JSON 配置文件载入参数
    bool load_from_file(const std::string & path);

    // 函数: load_from_string
    // 作用: 从 JSON 文本载入参数（便于测试与最小化重复解析）
    bool load_from_string(const std::string & json_text);

    // 函数: set_string
    // 作用: 设置一个字符串参数（通常由 CLI/测试注入）
    void set_string(const std::string & key, const std::string & value);

    // 函数: get_string
    // 作用: 获取字符串参数，若不存在返回 nullopt
    std::optional<std::string> get_string(const std::string & key) const;

    // 函数: get_bool
    // 作用: 获取布尔参数，若不存在返回 nullopt
    std::optional<bool> get_bool(const std::string & key) const;

    // 函数: get_double
    // 作用: 获取双精度浮点参数，若不存在返回 nullopt
    std::optional<double> get_double(const std::string & key) const;

    // 函数: get_frequencies
    // 作用: 获取频率列表（Hz）
    const std::vector<double> & get_frequencies() const { return _frequencies; }

    // 函数: get_num_groups
    // 作用: 获取计算分组数量（来自配置 N_GROUP）。若未设置则返回 nullopt。
    std::optional<int> get_num_groups() const { return _num_groups; }

    // 函数: 区域参数映射回读
    const std::unordered_map<int, double> & area_epsl_map() const { return _area_epsl; }
    const std::unordered_map<int, double> & area_cond_map() const { return _area_cond; }
    const std::unordered_map<int, double> & area_mu_map() const { return _area_mu; }

    // 函数: 各向异性映射回读
    const std::unordered_map<int, AnisotropySpecEntry> & area_aniso_conductivity() const
    {
        return _aniso_conductivity;
    }
    const std::unordered_map<int, AnisotropySpecEntry> & area_aniso_magnetic() const
    {
        return _aniso_magnetic;
    }
    const std::unordered_map<int, AnisotropySpecEntry> & area_aniso_dielectric() const
    {
        return _aniso_dielectric;
    }

    // 函数: get_layers
    // 作用: 获取层化模型描述
    const std::vector<LayerDepthConduction> & get_layers() const { return _layers; }

    // 函数: material_db
    // 作用: 材料数据库（可选）
    const MaterialDatabase & material_db() const { return _material_db; }

    // 函数: 求解器参数（可选返回）
    std::optional<double> get_solver_tolerance() const { return _solver_tolerance; }
    std::optional<int> get_solver_max_iterations() const { return _solver_max_iterations; }

    // 函数: boundary_specs
    // 作用: 返回 JSON 中解析出的边界条件规格（已经展开到具体边界 id）。
    // 说明: 若 JSON 未声明 BOUNDARY_CONDITIONS，则该列表为空；调用侧可据此决定回退逻辑。
    const std::vector<BoundarySpec> & boundary_specs() const { return _boundary_specs; }

    // 函数: has_collect_point
    // 作用: JSON 是否提供 COLLECT_POINT 规格
    bool has_collect_point() const { return _collect_point_spec.has_value(); }

    // 函数: collect_point_spec
    // 作用: 获取解析后的 COLLECT_POINT 规格（若存在）
    const std::optional<CollectPointSpec> & collect_point_spec() const
    {
        return _collect_point_spec;
    }

    // 函数: compute_collect_point_values
    // 作用: 基于 COLLECT_POINT 规格计算三轴的坐标数组。
    // 返回: 若未提供规格，则返回三轴均为空数组。
    CollectPointValues compute_collect_point_values() const;

private:
    // 解析帮助函数：从字符串解析边界条件类型（大小写不敏感），无效时返回 std::nullopt。
    std::optional<BoundaryType> parse_boundary_type_from_string(const std::string & s) const;

    std::unordered_map<std::string, std::string> _string_params; // CLI 字符串参数

    // legacy 区域参数
    std::unordered_map<int, double> _area_epsl;
    std::unordered_map<int, double> _area_cond;
    std::unordered_map<int, double> _area_mu;

    // 各向异性
    std::unordered_map<int, AnisotropySpecEntry> _aniso_conductivity;
    std::unordered_map<int, AnisotropySpecEntry> _aniso_magnetic;
    std::unordered_map<int, AnisotropySpecEntry> _aniso_dielectric;

    // 频率（Hz）
    std::vector<double> _frequencies;

    // 新增：分组数量（来自 JSON 的 N_GROUP）
    std::optional<int> _num_groups;

    std::vector<LayerDepthConduction> _layers;

    // 求解器参数（可选）
    std::optional<double> _solver_tolerance;   // 容忍度
    std::optional<int> _solver_max_iterations; // 最大迭代数

    // 新增：边界组映射与边界条件规格（由 JSON 指定）。
    std::vector<BoundarySpec> _boundary_specs; // 已展开到具体 id 的规格

    // 材料数据库占位（如需）
    MaterialDatabase _material_db;

    // COLLECT_POINT 规格
    std::optional<CollectPointSpec> _collect_point_spec;
};

} // namespace cem